"""
-*- coding: utf-8 -*-

@author: Du Changping
@time: 2021/12/6 16:41
@file name: gene_fbp
@software：PyCharm

Do not smash your computer!

"""

import os
import time
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt


def copy(path_1, path_2):
    """
    将路径path_1下的所有目录及文件复制到路径path_2下
    path_1: 待复制的目录或者文件路径
    path_2: 目标路径
    """
    if os.path.isdir(path_1):  # path_1是目录

        list_1 = os.listdir(path_1)
        if not list_1:  # 复制目录，仅仅是复制空目录
            os.mkdir(path_2)
        else:
            # os.mkdir(path_2)  # 先复制最上层空目录
            for i in list_1:
                path_r = os.path.join(path_1, i)  # 下层目录或文件的绝对路径
                path_w = os.path.join(path_2, i)  # 目标目录或文件的绝对路径
                if os.path.isfile(path_r):  # 是文件则直接进行复制
                    with open(path_r, 'rb') as rstream:
                        container = rstream.read()
                        with open(path_w, 'wb') as wstream:
                            wstream.write(container)
                else:  # 是目录则调用本函数
                    copy(path_r, path_w)

    else:  # path_1是文件
        with open(path_1, 'rb') as rstream:  # 是文件直接复制文件
            container = rstream.read()
            file_name = os.path.basename(path_1)
            path_2 = os.path.join(path_2, file_name)
            with open(path_2, 'wb') as wstream:
                wstream.write(container)
            wstream.close()
        rstream.close()


if __name__ == "__main__":
    timestamp = time.strftime("%m%d-%H%M%S", time.localtime())

    # basic setting
    # cur_dir = os.getcwd()
    whole_projection_dir = "fbp" + timestamp
    if not os.path.exists(whole_projection_dir):
        os.mkdir(whole_projection_dir)

    # file path setting todo
    input_dir_path = r"G:\CT_reco\week\homework1204\rec2\sgm"
    input_files_names = "sgm_test.raw"
    output_dir_name = r"rec" + timestamp
    output_dir_path = os.path.join(whole_projection_dir, output_dir_name)

    # sinogram setting todo
    SinogramWidth = 400
    SinogramHeight = 360
    Views = 360
    SliceCount = 1
    DetectorElementSize = 0.5

    # projection setting todo
    SourceIsocenterDistance = 100000
    SourceDetectorDistance = 100000

    # reconstruction setting unit: mm todo
    ImageDimension = 512
    PixelSize = 0.4

    # reconstruction kernel todo
    # 1. "HammingFilter": t + (1-t)*cos(pi*k/ 2*kn), 1 for ramp kernel, 0 for consine kernel, others are in-between
    # 2. "QuadraticFilter": (for bone-plus kernel) tow parameters for t and h, three parameters for a, b, c
    # 3. "Polynomial": an*k^n + ... + a1*k + a0, (n <= 6)
    #     (For Bone plus kernel: [ -15.9236, -2.1540, 3.1106, 2.3872, 1.0000 ], rebin detector element to 0.7 mm
    # 4.  "GaussianApodizedRamp": delta (delta=1 match MDCT if sinogram pixel size 0.4 mm),
    #     Ramp kernel apodized by a gaussian kernel (exp(-n^2/2/delta^2)), delta is in number of pixels
    kernel_str = "\"HammingFilter\": 0.5"
    # kernel_str = "\"GaussianApodizedRamp\": 1"

    # convert to HU value
    convert_to_HU = False

    # default parameters
    ImageRotation = 0
    ImageCenter = [0, 0]
    SaveFilteredSinogram = "false"
    DetectorOffcenter = 0

    # basic test
    original_sgm_file = os.listdir(input_dir_path)
    print(original_sgm_file)
    test_sgm_path = os.path.join(input_dir_path, original_sgm_file[0])
    test_sgm = np.fromfile(test_sgm_path, dtype=np.float32)
    assert test_sgm.shape[0] == SinogramWidth * SinogramHeight,\
        " please check the sinogram dimension, here test sgm's dimension is{}," \
        " while the set dimension is {}, {}, " \
        "its length is {}".format(test_sgm.shape[0],
                                  SinogramWidth, SinogramHeight,
                                  SinogramWidth*SinogramHeight)
    if not os.path.exists(output_dir_path):
        os.mkdir(output_dir_path)

    to_save_sgm_dir = whole_projection_dir + r"/sgm" + timestamp
    print(to_save_sgm_dir)
    if not os.path.exists(to_save_sgm_dir):
        os.mkdir(to_save_sgm_dir)
    copy(input_dir_path, to_save_sgm_dir)

    josnc_path = os.path.join(whole_projection_dir, "fbp.jsonc")
    f_ = open(josnc_path, "w")

    f_.write("// This is a config sample for mgfbp\n")
    f_.write("\n{\n")

    f_.write("  /*********************************************************\n")
    f_.write("  * input and output directory and files\n")
    f_.write("  *********************************************************/\n")
    f_.write("  \n")
    f_.write("  \"InputDir\": \"./{}\",\n".format(r"sgm"+timestamp))
    f_.write("  \"OutputDir\": \"./{}\",\n".format(output_dir_name))
    f_.write("  \n")
    f_.write("  // all the files in the input directory, use regular expression\n")
    f_.write("  \"InputFiles\": \"{}\",\n".format(input_files_names))
    f_.write("  // output file name (prefix, replace)\n")
    f_.write("  \"OutputFilePrefix\": \"{}\",\n".format(""))
    f_.write("  // replace substring in input file name\n")
    f_.write("  \"OutputFileReplace\": [ \"sgm_\", \"rec_\" ],\n")
    f_.write("  /*********************************************************\n")
    f_.write("    * sinogram and slice parameters\n")
    f_.write("    *********************************************************/\n")
    f_.write("  // number of detector elements\n")
    f_.write("  \"SinogramWidth\": {},\n".format(SinogramWidth))
    f_.write("  // number of frames\n")
    f_.write("  \"SinogramHeight\": {},\n".format(SinogramHeight))
    f_.write("  // number of views for reconstruction\n")
    f_.write("  \"Views\": {},\n".format(Views))
    f_.write("  // number of slices in each sinogram file\n")
    f_.write("  \"SliceCount\": {},\n".format(SliceCount))
    f_.write("  // the physical size of detector element size [mm]\n")
    f_.write("  \"DetectorElementSize\": {},\n".format(DetectorElementSize))
    f_.write("  \n")
    f_.write("  // source to isocenter distance [mm]\n")
    f_.write("  \"SourceIsocenterDistance\": {},\n".format(SourceIsocenterDistance))
    f_.write("  // source to detector distance [mm]\n")
    f_.write("  \"SourceDetectorDistance\": {},\n".format(SourceDetectorDistance))
    f_.write("  \n")
    f_.write("  /*********************************************************\n")
    f_.write("    * reconstruction parameters\n")
    f_.write("  *********************************************************/\n")
    f_.write("  // image dimension (integer)\n")
    f_.write("  \"ImageDimension\": {},\n".format(ImageDimension))
    f_.write("  // image pixel size [mm]\n")
    f_.write("  \"PixelSize\": {},\n".format(PixelSize))
    f_.write("  /* reconstruction kernel, avaliable list:\n")
    f_.write("  *  1. \"HammingFilter\": t + (1-t)*cos(pi*k/ 2*kn), 1 for ramp kernel,"
             " 0 for consine kernel, others are in-between\n")
    f_.write("  *  2. \"QuadraticFilter\": (for bone-plus kernel) tow parameters for t "
             "and h, three parameters for a, b, c\n")
    f_.write("  *  3. \"Polynomial\": an*k^n + ... + a1*k + a0, (n <= 6)\n")
    f_.write("  *     (For Bone plus kernel: [ -15.9236, -2.1540, 3.1106, 2.3872, 1.0000 ],"
             " rebin detector element to 0.7 mm\n")
    f_.write("  *  4.  \"GaussianApodizedRamp\": delta (delta=1 match MDCT if sinogram pixel size 0.4 mm),"
             " Ramp kernel apodized by a gaussian kernel (exp(-n^2/2/delta^2)), delta is in number of pixels\n")
    f_.write("  */\n")
    f_.write("  {},\n".format(kernel_str))
    f_.write("  \n\n")
    f_.write("  /*********************************************************\n")
    f_.write("	  * parameters by default\n")
    f_.write("  *********************************************************/\n")
    f_.write("  // rotate the image (positive counterclockwise) [degree]\n")
    f_.write("  \"ImageRotation\": {},\n".format(ImageRotation))
    f_.write("  // image center [x(mm), y(mm)]\n")
    f_.write("  \"ImageCenter\": {},\n".format(ImageCenter))
    f_.write("  \n")
    f_.write("  // (OPTIONAL) set water mu to convert the pixel values to HU\n")
    f_.write("  // unit: mm^-1\n")
    if not convert_to_HU:
        f_.write("  // \"WaterMu\": 0.0256,  // save filtered sinogram data\n")
    else:
        f_.write("  \"WaterMu\": 0.0256,  // save filtered sinogram data\n")
    f_.write("  \"SaveFilteredSinogram\": {},\n".format(SaveFilteredSinogram))
    f_.write("  \"DetectorOffcenter\": {},\n".format(DetectorOffcenter))
    f_.write("}\n")
